import pandas as pd

import util.util as utils

base_column = ['date', 'stock','close','trade_code','wg','tag','wg_industry',
               '15disPct','disPct',
            'week_pct','next_week_pct',
            'lp','rel_lp','category']

def util_new_empty_df():
    return pd.DataFrame({},columns=base_column)


def util_built(k, df):
    return {'date':df.iloc[-1].name,'trade_code':df.iloc[-1].trade_code,
                             'stock': k,
                            'close':df.iloc[-1].close,
                            'tag':df.iloc[-1].tag,
                            'wg_industry': df.iloc[-1].wg_industry,
                            'wg':df.iloc[-1].wg,
                            '15disPct':df.iloc[-1]['15dis_pct'],
                            'disPct':df.iloc[-1]['dis_pct'],
                            'category':df.iloc[-1].category,
                             'week_pct': df.iloc[-1].week_pct,
                            'next_week_pct': df.iloc[-1].next_week_pct,
                             'lp': df.iloc[-1].level_point,
                             'rel_lp': df.iloc[-1].rel_lp
                            }

def util_get_df(v, end):
    if end=='':
        return v
    if v.iloc[0].name < end:
        return v.loc[:end]
    return []


# 计算相差周数
def util_cal_duraton(start, end):
    s_year = start[0:4]
    s_week = start[6:8]
    
    e_year = end[0:4]
    e_week = end[6:8]
    
    return (int(e_year) - int(s_year))*52 + int(e_week) - int(s_week)


# 上穿 300 日线
def up300ds(data, end=''):
    ret = pd.DataFrame({},columns=base_column+['lplt10','duration','last_down_300d_duration','60w_gb'])
    for k,v in data.items():

        df = util_get_df(v, end)
        if len(df) == 0:
            continue
            
        if (df.iloc[-1].dis_pct >= 0) and (df.iloc[-1].pre_dis < 0):
            
            cur_item = util_built(k, df)
            cur_item['60w_gb'] = df.iloc[-1]['60w_gb']

            # 上穿 300 日线
            tmp = df[(df['dis_pct'] >= 0) & (df['pre_dis'] < 0)]
            cur_item['duration'] = 0
            # 上一次上穿 300 日线的日期
            if len(tmp) >= 2:
                # 计算两者的间隔的周数
                cur_item['duration'] = util_cal_duraton(tmp.iloc[-2].name, tmp.iloc[-1].name)
            
            # 最近一次跌破300日线
            de_df = df[(df['dis_pct'] < 0) & (df['pre_dis'] >= 0)]
            cur_item['last_down_300d_duration'] = 0
            if (len(de_df)) > 0:
                last_down_300d_duration = util_cal_duraton(de_df.iloc[-1].name,  tmp.iloc[-1].name)
                cur_item["last_down_300d_duration"] =  last_down_300d_duration 

            # 20个周期内是否有 lp 小于 10 的情况
            lplt10 = df[-21:]['level_point'].min() < 10
            cur_item['lplt10'] = 0
            if lplt10:
                print(k, lplt10)
                cur_item['lplt10'] = 1
            
            ret.loc[len(ret)] = cur_item

    return ret


# 上穿 75 日线
def up75ds(data, end=''):
    tmp = pd.DataFrame({},columns=base_column+['duration','last_down_75d_duration','15w_gb'])
    for k,v in data.items():

        df = util_get_df(v, end)
        if len(df) == 0:
            continue
            
        if (df.iloc[-1]["15dis_pct"] >= 0) and (df.iloc[-1]["15pre_dis"] < 0):

            cur_item = util_built(k, df)
            cur_item['15w_gb'] = df.iloc[-1]['15w_gb']

            # 最近一次跌破75日线
            de_df = df[(df['15dis_pct'] < 0) & (df['15pre_dis'] >= 0)]
            cur_item['last_down_75d_duration'] = 0
            if (len(de_df)) > 0:
                cur_item["last_down_75d_duration"] = util_cal_duraton(de_df.iloc[-1].name,  cur_item["date"])

            tmp.loc[len(tmp)] = cur_item


    return tmp

# 下穿 75 日线
def down75ds(data, end=''):
    tmp = pd.DataFrame({},columns=base_column+['15w_gb'])
    for k,v in data.items():

        df = util_get_df(v, end)
        if len(df) == 0:
            continue
            
        if (df.iloc[-1]["15dis_pct"]< 0) and (df.iloc[-1]["15pre_dis"] >= 0):
            cur_item = util_built(k, df)
            cur_item["15w_gb"] = df.iloc[-1]['15w_gb']

            tmp.loc[len(tmp)] = cur_item 
    return tmp

# 下穿 300 日线
def down300ds(data, end=''):
    tmp = pd.DataFrame({},columns=base_column+['60w_gb'])
    for k,v in data.items():

        df = util_get_df(v, end)
        if len(df) == 0:
            continue
            
        if (df.iloc[-1].dis_pct < 0) and (df.iloc[-1].pre_dis >= 0):
            cur_item = util_built(k, df)
            cur_item["60w_gb"] = df.iloc[-1]['60w_gb']

            tmp.loc[len(tmp)] = cur_item 

    return tmp


# 上穿300日线后的表现
def up300d_perform(data, end=''):

    ret = pd.DataFrame([], columns=['trade_code', 'stock'])

    for k,v in data.items():
        df = util_get_df(v,end)

        # 上穿 300 日线
        tmp = df[(df['dis_pct'] >= 0) & (df['pre_dis'] < 0)]
        if len(tmp) <= 0:
            continue

        tmp['duration'] = ''
        tmp['pre_date'] = ''
        # 上一次上穿 300 日线的日期
        if len(tmp) >= 2:
            tmp['pre_date'] = tmp.iloc[-2].name
            # 计算两者的间隔的周数
            tmp['duration'] = util_cal_duraton(tmp.iloc[-2].name, tmp.iloc[-1].name)
        
        #tmp['dis_pct'] = round(100 * df.iloc[-1].dis / df.iloc[-1]["60w_gb"], 2)

        # 目前还在 300日线上方
        if df.iloc[-1].dis_pct >= 0:
            tmp['300up'] = 1
        else:
            tmp['300up'] = 0

        # 突破后的涨跌幅
        data = df[tmp.iloc[-1].name:]
        tmp['increase'] = round(100 * (data['close'].max() - data.iloc[0].close) / data.iloc[0].close,2)

        # 最近上穿 300 日线
        ret = utils.merge(ret, pd.DataFrame(tmp[-1:]))

    return ret

#PB 统计
def week_pb_rank_statistic(data, end=''):
    ret = pd.DataFrame({},columns=base_column+['pb_ratio','pb_rank'])

    for k,v in data.items():

        # 指数、ETF没有PB数据
        if v.iloc[-1]['category'] != '股票':
            continue

        df = util_get_df(v, end)
        if len(df) < 1:
            continue

        print(k)
        rankData = df['pb_ratio'].tail(150).rank(method='min')
        curRankV = rankData.iloc[-1]
        if curRankV > 10:
            continue

        item = util_built(k, df)
        item['pb_ratio'] = df['pb_ratio'].iloc[-1]
        item['pb_rank'] = curRankV

        ret.loc[len(ret)] = item
    return ret

# 周涨跌统计
def week_statistic(data, end=''):
    ret = pd.DataFrame({},columns=base_column+['inc_num','pct_sum'])
    for k,v in data.items():

        df = util_get_df(v, end)
        if len(df) < 2:
            continue
        
        item = util_built(k, df)

        if (item['week_pct'] >= 0):
            count = 1
            in_sum = item['week_pct']
            try:
                while(df.iloc[-1*count - 1].week_pct >= 0):
                    in_sum += df.iloc[-1*count - 1].week_pct
                    count += 1
            except IndexError:
                pass

            item['inc_num'] = count
            item['pct_sum'] = in_sum
        else:
            # 计算下跌
            count = 1
            de_sum = item['week_pct']
            try:
                while(df.iloc[-1*count - 1].week_pct < 0):
                    de_sum += df.iloc[-1*count - 1].week_pct
                    count += 1
            except IndexError:
                pass

            item['inc_num'] = -1 * count
            item['pct_sum'] = de_sum

        ret.loc[len(ret)] = item
    
    ret.drop(columns=["wg","trade_code"], inplace=True)
    return ret

# 本周lp突破10的
def up10lp(data, end = ''):

    tmp = pd.DataFrame({},columns=base_column+['pre_date','duration','week_count'])

    for k,v in data.items():
        df = util_get_df(v, end)
        if len(df) < 2:
            continue

        if (df.iloc[-1].level_point >=10) and (df.iloc[-2].level_point < 10):
            new_item = util_built(k, df)

            # 计算之前持续几个周低于 10
            n = -1
            while len(df) > (-1 *n):
                first_item = df.iloc[n]
                if df.iloc[n-1].level_point > 10:
                    break
                n = n-1
            
            new_item['pre_date'] = first_item.name
            new_item['duration'] = util_cal_duraton(new_item['pre_date'],new_item['date'])
            new_item['week_count'] = len(df)
            
            tmp.loc[len(tmp)] = new_item

    return tmp


# 本周lp突破100的
def up100lp(data, end = ''):

    tmp = pd.DataFrame({},columns=base_column)

    for k,v in data.items():
        df = util_get_df(v, end)
        if len(df) < 2:
            continue

        if (df.iloc[-1].level_point >=99) and (df.iloc[-2].level_point < 99):
            new_item = util_built(k, df)
            tmp.loc[len(tmp)] = new_item

    return tmp

def nsmallest(data):
    ret = None
    for k,df in data.items():
        tmp = df.nsmallest(int(len(df) * 0.03),'pct_sum')
        if ret is None:
            ret = tmp
        else:
            ret = utils.merge(ret,tmp, False)
    
    return ret[["stock","wg_industry","close","week_pct","next_week_pct","pct_sum",
                "level_point","rel_lp",
                "15dis_pct","20dis_pct","30dis_pct","dis_pct",
                "category"]]

def dis_static(data):
    ret = None
    for k,df in data.items():
        if ret is None:
            ret = df[['dis_pct']].copy()

        ret.loc[k] = df['dis_pct']

    ret = ret.drop(['dis_pct'], axis=1)
    
    # 按日期倒序
    ret = ret[::-1]

    tmp = ret.T
    sortKey = tmp.columns.tolist()[0]
    tmp = tmp.sort_values(by=sortKey, ascending=False)
    
    return tmp.T


# 周 lp 统计
def lp_static(data):
    ret = None
    for k,df in data.items():
        if ret is None:
            ret = df[-350:][['level_point']]

        ret[k] = df[-350:]['level_point']

    ret = ret.drop(['level_point'], axis=1)

    # 按日期倒序
    ret = ret[::-1]

    # 获取最近的周
    print("排序周：", ret.T.columns.tolist()[0])

    tmp = ret.T
    sortKey = tmp.columns.tolist()[0]
    tmp = tmp.sort_values(by=sortKey, ascending=False)
    
    return tmp.T
